home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 051-075 / scopedisk68 / cmd4 / cmd4.src < prev   
C/C++ Source or Header  |  1995-03-19  |  22KB  |  768 lines

  1. --------------------------
  2. TITLE:  Cmd.c v4 (src and icon) - Redirects serial or parallel to a file
  3.  
  4.    For those of you who have asked for the ability to capture printer
  5. output in a file...
  6.  
  7.    Cmd redirects serial.device or parallel.device output to a file.
  8. This allows you to capture the printer output of many applications
  9. (including screen dumps) in a file.
  10.  
  11.    Cmd version 4 includes changes which allow Cmd to work with the
  12. HPLaser drivers which PWrite during a Forbid in their Close logic
  13. to print and eject the last sheet.
  14.  
  15.    Information on usage and options can be found in the initial comments
  16. and usage strings (u1[], u2[], ...) of Cmd.c.
  17.  
  18.    What follows are 3 files:
  19.       Cmd.with ---- Linkage info (Lattice) for Cmd
  20.       Cmda.asm ---- Assembler device function interface code
  21.       Cmd.c ------- The main program
  22.  
  23. FROM    LIB:Astartup.obj, cmd.o, cmda.o
  24. TO      cmd
  25. LIBRARY LIB:Amiga.lib,LIB:LC.lib
  26. ---------------------------- cut here ----------------------------------
  27.  
  28. *   cmda.asm  --- assembler interface for Cmd.c
  29. *                 Carolyn Scheppner --- CBM  05/87
  30.  
  31.    INCLUDE   'exec/types.i'
  32.  
  33.    XREF   _AbsExecBase
  34.    XREF   _MyBeginIO
  35.    XREF   _MyClose
  36.    XREF   _RealClose
  37.  
  38.    XDEF   _myBeginIO
  39.    XDEF   _myClose
  40.    XDEF   _myExpunge
  41.  
  42.    CODE
  43.  
  44.  
  45. _myBeginIO:
  46.    movem.l d0-d7/a0-a6,-(a7)   ;save registers
  47.  
  48.    move.l  a1,-(a7)            ;push ptr to io request
  49.    jsr     _MyBeginIO
  50.    addq.l  #4,a7
  51.  
  52.    movem.l (a7)+,d0-d7/a0-a6   ;restore registers
  53.    rts
  54.  
  55.  
  56. _myClose:
  57.    movem.l d0-d7/a0-a6,-(a7)   ;save registers
  58.  
  59.    move.l  a1,-(a7)            ;push ptr to io request
  60.    jsr     _MyClose
  61.    addq.l  #4,a7
  62.  
  63.    movem.l (a7)+,d0-d7/a0-a6   ;restore registers
  64.  
  65.    move.l  _RealClose,a0       ;continue to real Close
  66.    jmp     (a0)
  67.  
  68.  
  69. _myExpunge:
  70.    moveq.l #0,d0               ;means unable to expunge
  71.    rts                         ;keep changed device from being expunged
  72.  
  73.    END
  74.  
  75.  
  76. ---------------------------- cut here ----------------------------------
  77.  
  78. /* Cmd.c --- v4 --- Carolyn Scheppner  CBM  07/87
  79.  *
  80.  * Copyright (c) 1987  Commodore Business Machines - All Rights Reserved
  81.  *    This code may be freely non-commercially redistributed.
  82.  *
  83.  * Redirects exec serial or parallel device CMD_WRITEs to a file
  84.  *  (for the purpose of capturing printer output in a file)
  85.  * Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
  86.  *
  87.  * CLI Usage:  [run] cmd [-s] [-m] [-n] devicename filename
  88.  *   -s (Skip) skips any short initial write (usually a Reset if screendump)
  89.  *   -m (Multiple) causes cmd to remain installed for multiple files
  90.  *   -n (Notify) enables helpful progress messages 
  91.  *   devicename serial or parallel
  92.  *
  93.  * WB Usage:  Just doubleclick.
  94.  *            Specify the args in your icon's ToolTypes (use WB Info)
  95.  *            Built-in defaults are:
  96.  *               DEVICE=parallel
  97.  *               FILE=ram:CMD_file
  98.  *               SKIP=FALSE
  99.  *               MULTIPLE=FALSE
  100.  *               NOTIFY=FALSE
  101.  *
  102.  *   Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
  103.  *         The printer device then delays long enough for the reset
  104.  *         to complete, to prevent the loss of subsequent output data.
  105.  *         When the dump is instead captured in a file, this delay
  106.  *         is of course lost.  If your printer driver outputs a reset
  107.  *         at the start of a dump (as ours do), use the -s (SKIP) option
  108.  *         to keep the initial CMD_WRITE out of the file.
  109.  *
  110.  * Sorry about the busywait synchronization of the device wedge
  111.  * and the main process.  The purpose was to avoid unnecessary
  112.  * meddling with the message structures and the device's signals.
  113.  * I had to add a conditional kludge in MyBeginIO to allow Cmd
  114.  * to work with our HPLaser drivers which do PWrites within a Forbid
  115.  * in their Close logic to print/eject last sheet, and also apparently
  116.  * during their open logic if drivers are resident.
  117.  *
  118.  * v2 mods: changes to MyBeginIO for -1 and 0 length CMD_WRITES, usage
  119.  * v3 mods: added buffering of small writes to speed file IO
  120.  * v4 mods: Conditional kludges added to MyBeginIO for HPLaser
  121.  *          (if Forbidden, sneaks the data into main's write buffer)
  122.  *          (EXTRALEN added to wbuf size to allow extra room for this) 
  123.  *          myWrite now doesn't Write if len = 0
  124.  *          MyClose now conditional on writecnt, not reqcnt
  125.  *
  126.  * Linkage info (requires assembler module cmda):
  127.  * Compile with -v on LC2.
  128.  *    FROM    LIB:Astartup.obj, cmd.o, cmda.o
  129.  *    TO      cmd
  130.  *    LIBRARY LIB:Amiga.lib,LIB:LC.lib
  131.  */
  132.  
  133. #include "exec/types.h" 
  134. #include "exec/memory.h" 
  135. #include "exec/io.h"
  136. #include "exec/libraries.h"
  137. #include "exec/execbase.h"
  138. #include "libraries/dos.h" 
  139. #include "libraries/dosextens.h"
  140. #include "workbench/startup.h"
  141. #include "workbench/workbench.h"
  142. #include "devices/serial.h" 
  143. #include "devices/parallel.h" 
  144.  
  145. /* #define DEBUG */
  146.  
  147. #define TOUPPER(c)      ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c)) 
  148. #define HIGHER(x,y)     ((x)>(y)?(x):(y))
  149.  
  150. #define WBUFLEN   2048L
  151. #define EXTRALEN   256L
  152.  
  153. #define INBUFLEN    40L
  154. #define REQSIZE    120L    /* should be big enough or any OpenDevice */
  155.  
  156. #define DEV_CLOSE    LIB_CLOSE
  157. #define DEV_EXPUNGE  LIB_EXPUNGE
  158. /*      DEV_BEGINIO  (-30)       defined in exec/io.h */
  159.  
  160. #define OPEN_SIG   SIGBREAKF_CTRL_E
  161. #define WRITE_SIG  SIGBREAKF_CTRL_F
  162. #define CLOSE_SIG  SIGBREAKF_CTRL_D
  163. #define BREAK_SIG  SIGBREAKF_CTRL_C
  164.  
  165. #define SHORT_WRITE (8L)
  166.  
  167. extern VOID  myBeginIO();  /* The assembler entry */
  168. extern VOID  myClose();    /* The assembler entry */
  169. extern VOID  myExpunge();  /* The assembler routine */
  170.  
  171. extern struct ExecBase  *SysBase;
  172. extern struct MsgPort   *CreatePort(); 
  173. extern struct WBStartup *WBenchMsg;
  174.  
  175. ULONG  RealBeginIO, NewBeginIO;
  176. ULONG  RealClose,   NewClose;
  177. ULONG  RealExpunge, NewExpunge;
  178.  
  179. char *noMem      = "Out of memory\n";
  180. char *portName   = "cas_TMP_CMD_PORT";
  181. char *conSpec    = "CON:20/20/600/40/ CMD v4";
  182.  
  183. char u1[]={"\nCLI Usage: [run] Cmd [-s] [-m] [-n] devicename filename\n"};
  184. char u2[]={"  devicename = serial or parallel\n"};
  185. char u3[]={"  -s = SKIP any short initial write (usually a reset if screendump)\
  186. n"};
  187. char u4[]={"  -m = installed for MULTIPLE files until Break or CTRL_C\n"};
  188. char u5[]={"  -n = enables NOTIFY (helpful progress messages)\n\n"};
  189. char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
  190. char u7[]={"   Cancel installation for multiple files by reclicking\n\n"};
  191. char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
  192. char *morehelp = "Type  cmd ?  for more help\n\n";
  193.  
  194. char *prevTaskName = NULL;
  195. char *outFileName, *deviceName;
  196. char mainTaskName[40];
  197. char wbDev[INBUFLEN], wbFile[INBUFLEN];
  198. char sbuf[120], *wbuf = 0;
  199.  
  200. struct Device *TheDevice;
  201. struct Task   *otherTask, *mainTask;
  202.  
  203. struct IOStdReq *myReq, *ioR;
  204. struct MsgPort  *port; 
  205.  
  206.  
  207. LONG  wLen = 1, outFile = NULL;
  208. ULONG total = 0;
  209. ULONG IconBase = NULL;
  210. BOOL  Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
  211. BOOL  Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
  212. int   reqcnt = 0, writecnt = 0, filecnt = 0; fnLen, wi;
  213.  
  214. char cprt[] =
  215.  "Copyright (c) 1987  Commodore Business Machines  All Rights Reserved";
  216.  
  217. VOID MyBeginIO(ior)
  218. struct IOStdReq *ior;
  219.    {
  220.    BOOL   Forbidden;
  221.    char   *data;
  222.    int    k;
  223.  
  224.    /* The code conditional on Forbidden is needed to work with
  225.     * HPLaser drivers which PWrite during a Forbid in their Close
  226.     * logic to print and eject last sheet, and also apparently
  227.     * during the initial write if drivers are resident.
  228.     */
  229.    Forbidden = (SysBase->TDNestCnt >= 0) ? TRUE : FALSE;
  230.  
  231.    reqcnt += 1;
  232.    if((ior->io_Command == CMD_WRITE)&&(ior->io_Length))
  233.       {
  234.       writecnt += 1;
  235.  
  236.       if(writecnt==1)
  237.          {
  238.          if(!Forbidden)  while(MainBusy);
  239.          MainBusy = TRUE;
  240.          Signal(mainTask,OPEN_SIG);
  241.          if(!Forbidden)   while(MainBusy);
  242.          }
  243.  
  244.       /* If device CMD_WRITE uses length -1, convert to actual length */
  245.       if(ior->io_Length==-1)  ior->io_Length = strlen(ior->io_Data);
  246.  
  247.       if((!Skip)||(writecnt>1)||(ior->io_Length > SHORT_WRITE))
  248.          {
  249.          /* This conditional kludge needed to work with HPLaser
  250.           * drivers which PWrite during a Forbid in their
  251.           * Close logic to print/eject last sheet
  252.           */
  253.          if(Forbidden)
  254.             {
  255.             if(ior->io_Length < (WBUFLEN + EXTRALEN - wi))
  256.                {
  257.                data = (char *)ior->io_Data;
  258.                for(k=0; k<ior->io_Length; k++, wi++)  wbuf[wi]=data[k];
  259.                }
  260.             }
  261.          else
  262.             {
  263.             while(MainBusy);
  264.             MainBusy = TRUE;
  265.             ioR = ior;
  266.             Signal(mainTask,WRITE_SIG);  /* Signal write */
  267.             while(MainBusy);
  268.             }
  269.          }
  270.       ior->io_Actual = ior->io_Length;
  271.       }
  272.    if(!(ior->io_Flags & IOF_QUICK))  ReplyMsg(ior);
  273.    }
  274.  
  275.  
  276. VOID MyClose(ior)
  277. struct IOStdReq *ior;
  278.    {
  279.    /* Note - Exec has us in a forbid here */
  280.    if(writecnt) /* Ignores DOS's initial Open/Close/Open */
  281.       {
  282.       Signal(mainTask,CLOSE_SIG);  /* Signal Close */
  283.       }
  284.    }
  285.  
  286. main(argc, argv) 
  287. UWORD argc; 
  288. TEXT *argv[]; 
  289.    { 
  290.    ULONG signals;
  291.    int k;
  292.  
  293.    FromWb = (argc==0) ? TRUE : FALSE;
  294.  
  295.    if(FromWb)
  296.       {
  297.       getWbArgs(WBenchMsg);
  298.       deviceName  = wbDev;
  299.       outFileName = wbFile;
  300.       }
  301.    else
  302.       {
  303.       if(strEqu(argv[1], "?"))  usageHelpExit();
  304.       if(argc<3) usageExit();
  305.  
  306.       for(k=1; argv[k][0]=='-'; k++)
  307.          {
  308.          if(argv[k][1] == 's')  Skip = TRUE;
  309.          if(argv[k][1] == 'm')  Multiple = TRUE;
  310.          if(argv[k][1] == 'n')  Notify = TRUE;
  311.          }
  312.       if(argc-k < 2)  usageExit();
  313.       deviceName  = argv[k++];
  314.       outFileName = argv[k];
  315.       }
  316.  
  317.    fnLen = strlen(outFileName); /* Used if Multiple extension added */
  318.  
  319.    /* Result will be mainTaskName = "cas_CMD_whatever.device"
  320.     *   with deviceName pointing to the eighth character
  321.     */
  322.    strcpy(&mainTaskName[0],"cas_CMD_");
  323.    strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
  324.    strcpy(&mainTaskName[strlen(mainTaskName)],".device");
  325.    deviceName = &mainTaskName[8];
  326.  
  327.    Forbid();
  328.    if(otherTask = (struct Task *)FindTask(mainTaskName))
  329.       {
  330.       Permit();
  331.       if(FromWb) Signal(otherTask,BREAK_SIG);
  332.       else printf("Device already redirected... exiting\n");
  333.       cleanexit();
  334.       }
  335.  
  336.    mainTask = (struct Task *)FindTask(NULL);
  337.    prevTaskName = mainTask->tc_Node.ln_Name;
  338.    mainTask->tc_Node.ln_Name = mainTaskName;
  339.    Permit();
  340.      
  341.    /* initialize */
  342.    if(!(wbuf = (char *)AllocMem(WBUFLEN+EXTRALEN,MEMF_PUBLIC|MEMF_CLEAR)))
  343.       cleanexit("Can't allocate write buffer\n");
  344.    wi = 0;    /* index into wbuf */
  345.  
  346.    if(!(port = CreatePort(portName, 0)))  cleanexit("Can't open port\n");
  347.  
  348.    myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
  349.    if (!myReq)  cleanexit(noMem);
  350.  
  351.    myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  352.    myReq->io_Message.mn_ReplyPort = port;
  353.  
  354.    if(OpenDevice(deviceName, 0, myReq, 0))
  355.       {
  356.       sprintf(sbuf,"Can't open %s\n",deviceName);
  357.       cleanexit(sbuf);
  358.       }
  359.    TheDevice = myReq->io_Device;
  360.  
  361.    /* Install device IO redirection */
  362.  
  363.    Forbid();
  364.    RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
  365.    RealClose   = SetFunction(TheDevice, DEV_CLOSE,   myClose);
  366.    RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
  367.    Permit();
  368.  
  369.    /* Expunge disabled, CloseDevice so another can open it */
  370.    CloseDevice(myReq);
  371.  
  372.    if(Notify)
  373.       {
  374.       sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
  375.       message(sbuf);
  376.       }
  377.  
  378.    while(!Done)
  379.       {
  380.       signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
  381.  
  382.       if(signals & OPEN_SIG)   /* Open */
  383.          {
  384.          if(!outFile)   /* No output file currently open */
  385.             {
  386.             if(Multiple)  /* If Multiple, add .n extension to filename */
  387.                {
  388.                filecnt++;
  389.                sprintf(&outFileName[fnLen],".%ld",filecnt);
  390.                }
  391.              /* open output file */
  392.             outFile = Open(outFileName, MODE_NEWFILE);
  393.             wLen = 1;
  394.             total = 0;
  395.             /* This moved due to sneak-into-buffer HP kludge */
  396.             /* wi = 0;     Init now at Alloc, and each Close */
  397.             Error1 = TRUE;
  398.  
  399.             if(Notify)
  400.                {
  401.                sprintf(sbuf,"Redirecting %s to %s\n",
  402.                          deviceName,outFileName);
  403.                message(sbuf);
  404.                }
  405.  
  406.             }
  407. #ifdef DEBUG
  408.       printf("Processed OPEN_SIG, file %s, handle $%lx\n",
  409.                  outFileName,outFile);
  410. #endif
  411.          }
  412.  
  413.       if(signals & WRITE_SIG)   /* Write */
  414.          {
  415.          if((outFile)&&(wLen > -1))
  416.             {
  417.             wLen = bufOrWrite(outFile,ioR->io_Data,ioR->io_Length);
  418.             }
  419.          else if(Error1)
  420.             {
  421.             message("Cmd file error: Cancel device output\n");
  422.             Error1 = FALSE;
  423.             }
  424. #ifdef DEBUG
  425.       printf("Processed WRITE_SIG, ioLen %ld, wLen %ld, Error1 = %ld\n",
  426.                  ioR->io_Length, wLen, Error1);
  427. #endif
  428.          }
  429.  
  430.       if(signals & (CLOSE_SIG|BREAK_SIG))
  431.          {
  432.          /* Close file now so user can copy even if something is wrong */
  433.          /* Null the handle - to prevent Write or re-Close */
  434.          if(!Multiple)  signals |= BREAK_SIG;
  435.          if(outFile)
  436.             {
  437.             /* Write buffer contents */
  438.             if((wi>0)&&(wLen>-1)) wLen = myWrite(outFile,wbuf,wi);
  439.             wi = 0;    /* moved from Open logic */
  440.  
  441.             Forbid();
  442.             Close(outFile);
  443.             outFile = NULL;
  444.             writecnt = 0;
  445.             reqcnt = 0;
  446.             Permit();
  447.  
  448.             if((!Multiple)||(Notify))
  449.                {
  450.                sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
  451.                           total,deviceName,outFileName);
  452.                message(sbuf);
  453.                }
  454.             }
  455. #ifdef DEBUG
  456.       printf("Processed CLOSE_SIG, total %ld\n", total);
  457. #endif
  458.          }
  459.  
  460.       if(signals & BREAK_SIG)
  461.          {
  462. #ifdef DEBUG
  463.       printf("Got BREAK_SIG\n");
  464. #endif
  465.          while(!Done)
  466.             {
  467.             /* Wait till we can reopen the device */
  468.             while(OpenDevice(deviceName, 0L, myReq, 0L))  Delay(50L);
  469.  
  470.             /* If it's been re-loaded, we can leave            */
  471.             /* Shouldn't be possible since we disabled Expunge */
  472.             if((ULONG)myReq->io_Device != (ULONG)TheDevice)
  473.                {
  474.                Done = TRUE;
  475.                }
  476.             else
  477.                {
  478.                Forbid();
  479.  
  480.                NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
  481.                NewClose   = SetFunction(TheDevice, DEV_CLOSE,   RealClose);
  482.                NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
  483.  
  484.                if((NewBeginIO != (ULONG)myBeginIO)
  485.                    ||(NewClose != (ULONG)myClose)
  486.                      ||(NewExpunge != (ULONG)myExpunge))
  487.                   {
  488.                   /* Someone else has changed the vectors */
  489.                   /* We put theirs back - can't exit yet  */
  490.                   SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);              
  491.     SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  492.                   SetFunction(TheDevice, DEV_CLOSE,   NewClose);                
  493.   SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  494.                   SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
  495.                   }
  496.                else
  497.                   {
  498.                   Done = TRUE;
  499.                   }
  500.                Permit();
  501.                }
  502.             CloseDevice(myReq);
  503.             if(!Done)  message("Vectors have changed - can't restore\n");
  504.             }
  505.          }
  506.       MainBusy = FALSE;
  507.       }
  508.  
  509.    sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
  510.    cleanexit(sbuf);
  511.    }
  512.  
  513.  
  514. /* Output buffering */
  515.  
  516. bufOrWrite(fh,data,len)
  517. LONG fh;
  518. char *data;
  519. int len;
  520.    {
  521.    int k, wlen;
  522.  
  523.    wlen = len;
  524.  
  525.    /* If possible, just buffer the output data */
  526.    if(len <  WBUFLEN - wi)
  527.       {
  528.       for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  529.       }
  530.    else
  531.       {
  532.       /* Else output any buffered data to the file */
  533.       if(wi>0)  wlen = myWrite(fh,wbuf,wi);
  534.       wi = 0;
  535.  
  536.       /* Then either buffer or write out current request */
  537.       if(wlen > -1)
  538.          {
  539.          if(len < WBUFLEN)
  540.             {
  541.             for(k=0; k<len; k++, wi++)  wbuf[wi] = data[k];
  542.             wlen = len;
  543.             }
  544.          else
  545.             {
  546.             wlen = myWrite(fh,data,len);
  547.             }
  548.          }
  549.       }
  550.    return(wlen);
  551.    }
  552.  
  553.  
  554. /* myWrite also updates total */
  555. myWrite(fh,data,len)
  556. LONG fh;
  557. char *data;
  558. int len;
  559.    {
  560.    int wlen = 0;
  561.  
  562.    if(len)
  563.       {
  564.       wlen = Write(fh,data,len);
  565.       if (wlen > -1) total += wlen;
  566.       }
  567.    return(wlen);
  568.    }
  569.  
  570.  
  571. /* Cleanup and exits */
  572.  
  573. usageHelpExit()
  574.    { 
  575.    int k;
  576.    for(k=0; k<7; k++) printf(us[k]);
  577.    exit(RETURN_OK);
  578.    } 
  579.  
  580. usageExit()
  581.    { 
  582.    printf(u1);
  583.    printf(morehelp);
  584.    exit(RETURN_OK);
  585.    } 
  586.  
  587. cleanexit(s)
  588.    char  *s;
  589.    {
  590.    message(s);
  591.    cleanup();
  592.    exit(RETURN_OK);
  593.    }
  594.  
  595. cleanup()
  596.    {
  597.    if(myReq)   FreeMem(myReq,REQSIZE);
  598.    if(port)    DeletePort(port);
  599.    if(outFile) Close(outFile);
  600.    if(wbuf)    FreeMem(wbuf,WBUFLEN+EXTRALEN);
  601.  
  602.    Forbid();
  603.    if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
  604.    Permit();
  605.    }
  606.  
  607.  
  608. message(s)
  609. char *s;
  610.    {
  611.    LONG con;
  612.  
  613.    if((!FromWb)&&(*s)) printf(s);
  614.    if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
  615.       {
  616.       Write(con,s,strlen(s));
  617.       Delay(120L);
  618.       Close(con);
  619.       }
  620.    }
  621.  
  622.  
  623. getWbArgs(wbMsg)
  624. struct WBStartup *wbMsg;
  625.    {
  626.    struct WBArg  *wbArg;
  627.    struct DiskObject *diskobj;
  628.    char **toolarray;
  629.    char *s;
  630.  
  631.    /* Defaults */
  632.    strcpy(wbDev,"parallel");
  633.    strcpy(wbFile,"ram:CMD_file");
  634.    Skip = FALSE;
  635.    Multiple = FALSE;
  636.    Notify = FALSE;
  637.  
  638.    wbArg = wbMsg->sm_ArgList;
  639.  
  640.    if((IconBase = OpenLibrary("icon.library", 0)))
  641.       {
  642.       diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
  643.       if(diskobj)
  644.          {
  645.          toolarray = (char **)diskobj->do_ToolTypes;
  646.  
  647.          if(s=(char *)FindToolType(toolarray,"DEVICE"))  strcpy(wbDev,s);
  648.          if(s=(char *)FindToolType(toolarray,"FILE"))    strcpy(wbFile,s);
  649.          if(s=(char *)FindToolType(toolarray,"SKIP"))
  650.             {
  651.             if(strEqu(s,"TRUE"))  Skip = TRUE;
  652.             }
  653.          if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
  654.             {
  655.             if(strEqu(s,"TRUE"))  Multiple = TRUE;
  656.             }
  657.          if(s=(char *)FindToolType(toolarray,"NOTIFY"))
  658.             {
  659.             if(strEqu(s,"TRUE"))  Notify = TRUE;
  660.             }
  661.          FreeDiskObject(diskobj);
  662.          }
  663.       CloseLibrary(IconBase);
  664.       }
  665.    }
  666.  
  667.  
  668. /* String functions */
  669.  
  670. strEqu(p, q) 
  671. TEXT *p, *q; 
  672.    { 
  673.    while(TOUPPER(*p) == TOUPPER(*q))
  674.       {
  675.       if (*(p++) == 0)  return(TRUE);
  676.       ++q; 
  677.       }
  678.    return(FALSE);
  679.    } 
  680.  
  681. strlen(s)
  682. char *s;
  683.    {
  684.    int i = 0;
  685.    while(*s++) i++;
  686.    return(i);
  687.    }
  688.  
  689. strcpy(to,from)
  690. char *to, *from;
  691.    {
  692.    do
  693.       {
  694.       *to++ = *from;
  695.       }
  696.    while(*from++);
  697.    }
  698.  
  699. /* end */
  700.  
  701. ------------------------------- cut here -------------------------------------
  702. TITLE:  Cmd.uu v4 (exec. and icon) - Redirects serial or parallel to file
  703.  
  704.    For those of you who have asked for the ability to capture printer
  705. output in a file...
  706.  
  707.    What follows are two uuencoded files for my Cmd.info and Cmd.
  708.  
  709.    Cmd redirects serial.device or parallel.device output to a file.
  710. This allows you to capture the printer output of many applications
  711. (including screen dumps) in a file.
  712.  
  713.    Cmd version 4 includes changes which allow Cmd to work with the
  714. HPLaser drivers which PWrite during a Forbid in their Close logic
  715. to print and eject the last sheet.
  716.  
  717. CLI Usage: [run] Cmd [-s] [-m] [-n] parallel|serial filename
  718.            (or  Cmd ?  for help)
  719.  
  720.   Example: run Cmd -m -n parallel ram:pfile
  721.            To end a multiple (-m) Cmd, CTRL-C, or use BREAK if run
  722.  
  723. Workbench: Just double click.  All args specified in .info ToolTypes.
  724.               Workbench defaults:
  725.                  DEVICE=parallel
  726.                  FILE=ram:CMD_file
  727.                  SKIP=FALSE
  728.                  MULTIPLE=FALSE
  729.                  NOTIFY=FALSE
  730.            To end a MULTIPLE Cmd, double-click CMD again
  731.  
  732. Options (CLI or Workbench ToolTypes):
  733.  
  734.    -s (ToolTypes: SKIP=TRUE)
  735.  
  736.       If the -s (SKIP) option is specified, Cmd will ignore an initial
  737.       short (less than 8 bytes) write to the device and not save that
  738.       write in the file.  This option is useful when capturing a
  739.       screen dump because most of our drivers currently send a Reset
  740.       string to the printer before the dump.  The driver then delays
  741.       so that subsequent data sent is not lost.  When the dump is
  742.       captured in a file, this programmatic delay is lost and the
  743.       following bytes are endangered by the reset.  In most cases,
  744.       this option should prevent the Reset string from being stored
  745.       in the Cmd file.  You should be able to copy the resulting file
  746.       directly to PAR: (or SER:) for a quick dump.
  747.  
  748.    -m (Tooltypes: MULTIPLE=TRUE)
  749.  
  750.       If the -m (MULTIPLE) option is not specified, the file is closed
  751.       and the redirection removed when the device is closed by the
  752.       application.  With the -m option, Cmd remains installed and
  753.       opens a new file (with .n extension) each time the device is
  754.       opened.
  755.  
  756.    -n (Tooltypes: NOTIFY=TRUE)
  757.  
  758.       The -n (NOTIFY) option causes output of progress messages about
  759.       the redirection.  I like noisy utilities but many others don't,
  760.       so it's an option. 
  761.  
  762.  
  763. Cmd - Copyright (c) 1987 Commodore Business Machines - All Rights Reserved
  764. This program may be freely non-commercially redistributed.
  765. Only warranty is works fine for me --- Carolyn Scheppner
  766.  
  767.  
  768.